#include "CoCoA/library.H"
#include <cstdlib>

using namespace CoCoA;
using namespace std;

//bool mystrcmp(const string& str1,const string& str2) {
//return str1.compare(str2)<>0 
//}
typedef set<string> StrSet;
const static string symbolchars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const static string other="()*+-^ \t\n";
const static string ops="()*+-^";
const static string digits="1234567890";
const static size_t szDeg=sizeof(long); //the maximal size of degree
StrSet ParseSymbols(const str& str){
	StrSet heads;
	for (size_t b=str.find_first_of(symbolchars); b!=string::npos;){
		 size_t e=str.find_first_not_of(symbolchars,b);	
		 if (e!=string::npos)
		 {
			heads.insert(string(str,b,e-b));
		  b=str.find_first_of(symbolchars,e);
		}
		else 
		{
			heads.insert(string(str,b,str.length()-b+1));
					break;
					}
	}
	return heads;
}
//a input polynomial is consisted by symbols and +,-,*,^,()
//a^2*(b+c)
RingElim string2poly(const string& str){
	vector<symbol> vars;
	StrSet heads;
	const string symbolchars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
	const string other="()*+-^ \t\n\r";
	for (StrSet::const_iterator i=heads.begin(); i!=heads.end(); i++)
			vars.insert(symbol(*i));
  	SparsePolyRing P = NewPolyRing(RingQ(),vars);
	RingElim f=0;

}


RingElim string2poly_recursive(const string& str, const StrSet& symbols, const SparsePolyRing& P){
		
		size_t b=find_first_of(other,str);
		if b=string::npos {
		}
		if str[found]
}

//check the type of basic token: symbol 's' or big integer 'I' of machine integer 'i'
//currently, do not check of invalid input by this point
char TokenType(const string& str){
	size_t b=str.find_first_not_of(digits);
	if (b!=string::npos){
		return 's'
	}
	else if (str.length()<szDeg)
			return 'i';
		else return 'I';
		
}

ZZ Str2ZZ(const string & str){
	ZZ z;
	istringstream Str(str);
	Str>>z;
	return z;
}

//throw bad input expection

size_t FindFirstRight(const string& str, size_t pos=0) {
	size_t left=0;
	for (size_t b=str.find_first_of("()",pos); b!=string::npos;
				b=str.find_first_of("()",b+1)	
					){
			if (b!=string::npos) {
			if (str[b]=='(')
				left+=1;
			else {
				if (left==0) 
						return b;
				else left-=1;
			}
			}
			//else throw("found non paired parenthese!");
			else return b;
	}
	return b;
}

vector<size_t> Skeleton(const string& str) {
	vector<size_t> stn;
	size_t pre=0;
	size_t b=str.find_first_of(ops);
	while (b!=string::npos){
		if (str[b]=='(')
			b=FindFirstRight(str,b+1);
		else 
		{stn.insert(stn.end(),b-pre);
			pre=b;
		}
		b=str.find_first_of(ops,b+1);
	}
	return stn;
}



//expection not a valid input
//pivot=0 iff of type (poly) or -term or -(poly)
//pivot char= *,+,^,(,
//pivot npos: non invalid input
size_t PolyStrPivot(const string& str){
	size_t b=str.find_first_of(other);
	if (b=string::npos)
			return b;
	else
			bool cont=true;
		while (cont) 
		switch (str[b])
      {
         case '*':
			b:
            break;
		case '(':
			e=FindFirstRight(str,b+1);
			if (e!=string::npos)
					if (e==str.length())
							return b;
					else 
							switch(str[e+1]){
									case '+':
									case '-':
									return e+1;
									case '^':
									b=str.find_first_of(other,e+1);
							;
							}
			else
				throw ("invalid input");
					;
			break;
		case ')':
			throw ("invalid input");
         case '-':
			if (b==0) {

					break;
			}
         case '^':
         default:
			return b;
      }
			case 
			;
}

size_t FindPlusPivot(const string& str){
	size_t b=str.find_first_of(other);
	while (b!=string::npos){
		switch(str[b]){
			case ')':
					throw("invalid input!");
			case '+':
			return b;
			case '-':
				if (b!=0) {
						return b;
						break;
				}
			case '(':
					b=FindFirstRight(str,b+1);
			default:
					b=str.find_first_of(other,b+1);
		}
	}
	return b;		
}


/*void PlusSplit(const string& str, string* str1, string* str2,size_t pos) {
	if (pos=string::npos){
	}
	else {

	}
}
*/
size_t FindPowerPivot(const string& str){
	size_t b=str.find_first_of(other);
	while (b!=string::npos){
		switch(str[b]){
			case ')':
					throw("invalid input!");
			case '+':
			return b;
			case '-':
				if (b!=0) {
						return b;
						break;
				}
				/*else 
						b=str.find_first_of(other,b+1);
						*/
			case '(':
					b=FindFirstRight(str,b+1);
			
			/*case '^':
			case '*':
			case ' ':
			case '\t':
			case '\r':
			case '\n':
			*/
			default:
					b=str.find_first_of(other,b+1);
		}
	}
	return b;		
}
}



void program()
{
  GlobalManager CoCoAFoundations;
  vector<symbol> vars;
  vars.insert(vars.end(),symbol("x"));
  vars.insert(vars.end(),symbol("y"));
  cout << "x1 is " << bool2string(symbol::IsValidHead("x1")) << " a symbol" << endl; 
  cout << "xy is " << bool2string(symbol::IsValidHead("xy")) << " a symbol" << endl; 
  SparsePolyRing P = NewPolyRing(RingQ(),vars) ; // QQ[x,y];
  const vector<RingElem>& x = indets(P);
  RingElem f = power(x[0],96) - power(x[1],96); // f = x^96-y^96
  RingElem g = power(x[0],95) - power(x[1],95); // f = x^96-y^96
  RingElem d = gcd(f,g);
  // FacInfo contains 3 fields:
  //   myFactors         - a vector of irreducible factors
  //   myExponents       - a vector of the corresponding multiplicities
  //   myRemainingFactor - an unfactored part (e.g. the content)

  GlobalOutput() << "The gcd of " << f << " and "<< g << " is:" << d << endl;
}

//----------------------------------------------------------------------
// Use main() to handle any uncaught exceptions and warn the user about them.
int main()
{
  try
  {
    program();
    return 0;
  }
  catch (const CoCoA::ErrorInfo& err)
  {
    GlobalErrput() << "***ERROR***  UNCAUGHT CoCoA error";
    ANNOUNCE(err);
  }
  catch (const std::exception& exc)
  {
    GlobalErrput() << "***ERROR***  UNCAUGHT std::exception: " << exc.what() << endl;
  }
  catch(...)
  {
    GlobalErrput() << "***ERROR***  UNCAUGHT UNKNOWN EXCEPTION" << endl;
  }
  return 1;
}


